﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Timers;
using System.Diagnostics;
using Styx.XmlEngine;
using System.Runtime.InteropServices;
using Styx.CommonBot.POI;
using Styx.WoWInternals.World;


using Styx;
using Styx.TreeSharp;
using Styx.Helpers;
using Styx.WoWInternals;
using Styx.WoWInternals.WoWObjects;
using Styx.CommonBot;
using Styx.Common;
using Styx.Resources;
using Styx.Loaders;
using Styx.Common.Helpers;
using Styx.Pathing;
using CommonBehaviors.Actions;

using Action = Styx.TreeSharp.Action;

namespace DWCC
{
    public partial class Warrior
    {
        #region SpellCaster
        public Composite CreateSpellCheckAndCast(string name, CanRunDecoratorDelegate extra)
        {
            return new Decorator(ret => extra(ret) && SpellManager.HasSpell(name) && SpellManager.CanCast(name) && Me.IsFacing(Me.CurrentTarget) && Me.CurrentTarget.IsWithinMeleeRange,
                                 new Action(delegate
                                 {
                                     SpellManager.Cast(name);
                                     Logging.Write(System.Windows.Media.Color.FromArgb(0xFF, 0xFF, 0xA5, 0x00), "[DWCC]: " + name);
                                     Logging.WriteDiagnostic("[DWCC]: Attempting to cast " + name + " on " + Me.CurrentTarget.Name.Remove(3, Me.CurrentTarget.Name.Length - 3) + "*** @ " + Me.CurrentTarget.CurrentHealth + "/" + Me.CurrentTarget.MaxHealth + " (" + Math.Round(Me.CurrentTarget.HealthPercent, 2) + "%)");
                                     Logging.WriteDiagnostic("[DWCC]: Target: IsCasting: " + Me.CurrentTarget.IsCasting + " | IsPlayer: " + Me.CurrentTarget.IsPlayer + " | Distance: " + Math.Round(Me.CurrentTarget.Distance, 2) + " | Level: " + Me.CurrentTarget.Level + " | IsElite: " + Me.CurrentTarget.Elite + " | Adds: " + detectAdds().Count);
                                     Logging.WriteDiagnostic("[DWCC]: We are in: " + Me.ZoneText + " | Instance: " + Me.IsInInstance + " | Outdoors: " + Me.IsOutdoors + " | Battleground: " + Styx.WoWInternals.Battlegrounds.IsInsideBattleground + " | Indoors: " + Me.IsIndoors + " | Party: " + Me.GroupInfo.IsInParty + " | Raid: " + Me.GroupInfo.IsInRaid + " | Members: " + Me.PartyMembers.Count + "/" + Me.RaidMembers.Count + " | Health: " + Me.CurrentHealth + "/" + Me.MaxHealth + " (" + Math.Round(Me.HealthPercent, 2) + "%) | BattleStance: " + BattleStance + " | DefStance: " + DefStance + " | BerserkerStance: " + BersiStance);
                                 }
                                     ));
        }
        public uint Stacks(string Aura)
        {
            if (Me.HasAura(Aura)) return Me.Auras[Aura].StackCount;
            else return 0;
        }
        public double AuraTimeLeft(string Aura)
        {
            if (Me.HasAura(Aura)) return Me.Auras[Aura].TimeLeft.TotalSeconds;
            else return 0;
        }
        #endregion
        #region Movement
        TimeSpan MovementDelay = TimeSpan.FromSeconds(3f);
        DateTime LastMovement;
        WoWPoint LastMovementPoint;
        public Composite MoveToTarget()
        {
            return new Decorator(ret => 
                Me.CurrentTarget.IsHostile &&
                !DunatanksSettings.Instance.DisableMovement &&
                Me.CurrentTarget.Distance > 5f &&
                ((DateTime.Now > LastMovement + MovementDelay) || 
                (LastMovementPoint.Distance(Me.CurrentTarget.Location) > 5f)),
                new Sequence(
                    new Action(ret => LastMovementPoint = Me.CurrentTarget.Location),
                    new Action(ret => LastMovement = DateTime.Now),
                    new Action(ret => Logging.Write(System.Windows.Media.Color.FromRgb(0xFF, 0x00, 0x00), "Distance: " + Me.CurrentTarget.Distance + " Meleerange: " + Me.CurrentTarget.IsWithinMeleeRange)),
                    new Action(ret => Me.CurrentTarget.Face()),
                    new Action(ret => Navigator.MoveTo(Me.CurrentTarget.Location))));
            /*return new Decorator(ret => Me.CurrentTarget.IsHostile,
                new PrioritySelector(
                    new Decorator(ret => Me.CurrentTarget != null && !DunatanksSettings.Instance.DisableMovement && (Me.CurrentTarget.IsWithinMeleeRange || Me.CurrentTarget.Distance < 5f) && Me.IsMoving && !AreaSpells() && !Me.IsGhost,
                    //Already in Meelee Range? MoveStop.
                        new Sequence(
                            new Action(ret => Navigator.PlayerMover.MoveStop()),
                            new Action(ret => CreateAutoAttack()))),
                    new Decorator(ret => !DunatanksSettings.Instance.DisableMovement && !Me.CurrentTarget.IsWithinMeleeRange || !Me.CurrentTarget.InLineOfSight && Me.CurrentTarget != null && Me.CurrentTarget.IsCasting && Me.CurrentTarget.CurrentTarget == Me,
                    //My target is casting at me? Move there.
                        new Action(ret => Navigator.MoveTo(Me.CurrentTarget.Location))),
                    new Decorator(ret => !DunatanksSettings.Instance.DisableMovement && !Me.CurrentTarget.IsWithinMeleeRange || !Me.CurrentTarget.InLineOfSight && Me.CurrentTarget != null,
                    //Not in Meeleerange? GET THERE.
                        new Action(ret => Navigator.MoveTo(Me.CurrentTarget.Location))),
                    new Decorator(ret => !DunatanksSettings.Instance.DisableMovement && Me.CurrentTarget.IsWithinMeleeRange && !Me.IsFacing(Me.CurrentTarget),
                    //In Meeleerange but not facing? Face.
                        new Action(ret => Me.CurrentTarget.Face())),
                    new Decorator(ret => (Me.CurrentTarget.IsWithinMeleeRange && Me.IsFacing(Me.CurrentTarget) && !Me.IsAutoAttacking) || (Me.IsDead && Me.IsGhost),
                    //In Range, Facing but not attacking? Attack.
                        new Sequence(
                            new Action(ret => Navigator.PlayerMover.MoveStop()),
                            new Action(ret => CreateAutoAttack())))
            ));*/
        }

        #region WaitForFleeing
        public Composite WaitForFleeingTarget()
        {
            return new PrioritySelector(
                new Decorator(ret => !DunatanksSettings.Instance.DisableMovement && Me.CurrentTarget != null && !AreaSpells() && IsFleeing(Me.CurrentTarget),
                //My target is fleeing & not in melee range? Wait for it to either come back to melee range or flee to charge range
                  new Sequence(
                    new Action(ret => Navigator.PlayerMover.MoveStop()))),
            new Decorator(ret => !DunatanksSettings.Instance.DisableMovement && SpellManager.HasSpell("Charge") && !SpellManager.Spells["Charge"].Cooldown && SpellManager.CanCast("Charge") && Me.CurrentTarget.Distance > 13f && Me.CurrentTarget.Distance < 25f && Me.IsFacing(Me.CurrentTarget),
                 new Action(ret => SpellManager.Cast("Charge"))),
            new Decorator(ret => !DunatanksSettings.Instance.DisableMovement && SpellManager.HasSpell("Charge") && !SpellManager.Spells["Charge"].Cooldown && SpellManager.CanCast("Charge") && Me.CurrentTarget.Distance > 13f && Me.CurrentTarget.Distance < 25f && !Me.IsFacing(Me.CurrentTarget),
                 new Sequence(
                    new Action(ret => Me.CurrentTarget.Face()),
                    new Action(ret => SpellManager.Cast("Charge")))),
            new Decorator(ret => !DunatanksSettings.Instance.DisableMovement && SpellManager.HasSpell("Heroic Throw") && !SpellManager.Spells["Heroic Throw"].Cooldown && SpellManager.CanCast("Heroic Throw") && Me.CurrentTarget.Distance > 8 && Me.CurrentTarget.Distance < 25 && Me.IsFacing(Me.CurrentTarget),
                 new Action(ret => SpellManager.Cast("Heroic Throw"))),
            new Decorator(ret => !DunatanksSettings.Instance.DisableMovement && SpellManager.HasSpell("Heroic Throw") && !SpellManager.Spells["Heroic Throw"].Cooldown && SpellManager.CanCast("Heroic Throw") && Me.CurrentTarget.Distance > 8 && Me.CurrentTarget.Distance < 25 && !Me.IsFacing(Me.CurrentTarget),
                 new Sequence(
                    new Action(ret => Me.CurrentTarget.Face()),
                    new Action(ret => SpellManager.Cast("Heroic Throw"))))
            );
        }
        #endregion
        #region StopMoving
        public Composite StopMoving()
        {
            return new Decorator(ret => !DunatanksSettings.Instance.DisableMovement && (Me.CurrentTarget.IsWithinMeleeRange || Me.CurrentTarget.Distance < 5f) && Me.IsMoving && !AreaSpells() && !Me.IsGhost,
                new Sequence(
                    new Action(ret => Navigator.PlayerMover.MoveStop()),
                    new Action(ret => CreateAutoAttack()),
                    new ActionAlwaysSucceed()));
        }
        #endregion
        #endregion
        #region Heroic Leap
        public Composite HeroicLeap()
        {
            return new Decorator(ret => SpellManager.CanCast("Heroic Leap") && Navigator.CanNavigateFully(Me.Location, Me.CurrentTarget.Location) && (((Me.Location.Z - Me.CurrentTarget.Location.Z) < 3) && ((Me.Location.Z - Me.CurrentTarget.Location.Z) > -3)) && Me.CurrentTarget != null && Me.CurrentTarget.IsHostile && !Me.CurrentTarget.IsFlying && Me.CurrentTarget.Attackable && Me.CurrentTarget.InLineOfSight && !Me.CurrentTarget.HasAura("Charge Stun") && Me.CurrentTarget.Distance < 40 && Me.CurrentTarget.Distance >= 8 && !DunatanksSettings.Instance.DisableMovement,
            new Sequence(
                new Action(delegate
                    {
                        SpellManager.Cast("Heroic Leap");
                        SpellManager.ClickRemoteLocation(Me.CurrentTarget.Location);
                        MoveToTarget();
                    }),
                new Action(a => Logging.Write("[DWCC]: Heroic Leap. Distance: " + Math.Round(Me.CurrentTarget.Distance, 2) + " LoS: " + Me.CurrentTarget.InLineOfSight))
            ));
        }
        #endregion  
        #region Charge
        WoWPoint preCharge;
        bool NeedMove;
        public Composite CastCharge()
        {
            return new Decorator(ret => SpellManager.CanCast("Charge") && !DunatanksSettings.Instance.DisableMovement && Me.CurrentTarget.InLineOfSight && Me.CurrentTarget.InLineOfSpellSight && Me.CurrentTarget.Distance > 13f && Me.CurrentTarget.Distance < 25f && !DunatanksSettings.Instance.DisableMovement,
                new Sequence(
                    new Action(delegate
                        {
                            preCharge = Me.Location;
                            SpellManager.Cast("Charge");
                            if (Me.Location == preCharge) NeedMove = true;
                        }),
                    new Action(a => Logging.Write("[DWCC]: Charge. Distance: " + Math.Round(Me.CurrentTarget.Distance, 2))),
                    new Action(a => Logging.WriteDiagnostic("[DWCC]: Attempting to cast Charge on " + Me.CurrentTarget.Name.Remove(3, Me.CurrentTarget.Name.Length - 3) + "*** @ " + Me.CurrentTarget.CurrentHealth + "/" + Me.CurrentTarget.MaxHealth + " (" + Math.Round(Me.CurrentTarget.HealthPercent, 2) + "%)")),
                    new Action(a => Logging.WriteDiagnostic("[DWCC]: Target: IsCasting: " + Me.CurrentTarget.IsCasting + " | IsPlayer: " + Me.CurrentTarget.IsPlayer + " | Distance: " + Math.Round(Me.CurrentTarget.Distance, 2) + " | Level: " + Me.CurrentTarget.Level + " | IsElite: " + Me.CurrentTarget.Elite + " | Adds: " + detectAdds().Count)),
                    new Action(a => Logging.WriteDiagnostic("[DWCC]: We are in: " + Me.ZoneText + " | Instance: " + Me.IsInInstance + " | Outdoors: " + Me.IsOutdoors + " | Battleground: " + Styx.WoWInternals.Battlegrounds.IsInsideBattleground + " | Indoors: " + Me.IsIndoors + " | Party: " + Me.GroupInfo.IsInParty + " | Raid: " + Me.GroupInfo.IsInRaid + " | Members: " + Me.PartyMembers.Count + "/" + Me.RaidMembers.Count + " | Health: " + Me.CurrentHealth + "/" + Me.MaxHealth + " (" + Math.Round(Me.HealthPercent, 2) + "%) | BattleStance: " + BattleStance + " | DefStance: " + DefStance + " | BerserkerStance: " + BersiStance)),
                    new WaitContinue(1, ret => false, new ActionAlwaysSucceed())
                    ));
        }
        #endregion
        #region Enrage
        public bool IsEnraged(WoWUnit unit)
        {
            return Me.GetAllAuras().Any(
                a => a.Spell.Mechanic == WoWSpellMechanic.Enraged
                      );
        }
        #endregion
        #region Add Detection
        //Credit to CodeNameGamma for detectAdds code
        private List<WoWUnit> detectAdds()
        {
            List<WoWUnit> addList = ObjectManager.GetObjectsOfType<WoWUnit>(false).FindAll(unit =>
                        unit.Guid != Me.Guid &&
                        unit.Distance < DunatanksSettings.Instance.CombatDistance &&
                        unit.IsAlive &&
                        (unit.Combat || unit.Name.Contains("Training Dummy") || unit.IsTotem || unit.IsPlayer) &&
                        !unit.IsPet &&
                        !unit.IsFriendly &&
                        unit.Attackable &&
                        !Styx.CommonBot.Blacklist.Contains(unit.Guid));
            //Logging.Write(addList.Count.ToString());


            return addList;
        }
        #endregion
        #region Bloodsurge
        public bool Bloodsurge()
        {
            if (Me.HasAura(46916)) return true;
            else return false;
        }
        #endregion
        #region Stances
        public bool BattleStance
        {
            get
            {
                if (StyxWoW.Me.HasAura(2457))
                {
                    return true;
                }
                return false;
            }
        }

        public bool DefStance
        {
            get
            {
                if (StyxWoW.Me.HasAura(71))
                {
                    return true;
                }
                return false;
            }
        }

        public bool BersiStance
        {
            get
            {
                if (StyxWoW.Me.HasAura(2458))
                {
                    return true;
                }
                return false;
            }
        }
        #endregion
        #region IsTank
        public bool TargetTargetIsTank()
        {
            WoWPlayer PotentialTank = null;
            if (Me.CurrentTarget.CurrentTarget.IsPlayer && Me.CurrentTarget.CurrentTarget != Me)
            {
                PotentialTank = Me.CurrentTarget.CurrentTarget.ToPlayer();
                if (PotentialTank.Type.Equals(SpecType.Tank))
                {
                    Logging.WriteDiagnostic("[DWCC]: IsTank Check: My target: " + Me.CurrentTarget.Name + " . His target is: " + Me.CurrentTarget.CurrentTarget.Name + ". He is a Tank.");
                    return true;
                }
                else
                {
                    Logging.WriteDiagnostic("[DWCC]: IsTank Check: My target: " + Me.CurrentTarget.Name + " . His target is: " + Me.CurrentTarget.CurrentTarget.Name + ". He is NOT a Tank.");
                    return false;
                }
            }
            return false;
        }
        #endregion
        #region AutoAttack
        public static Composite CreateAutoAttack()
        {

            return new Decorator(ret => !Me.IsAutoAttacking && Me.CurrentTarget.IsWithinMeleeRange,
                new Action(ret => Me.ToggleAttack()));
        }
        #endregion
        #region UnitSelection
        public delegate WoWUnit UnitSelectDelegate(object context);
        #endregion
        #region FaceTarget
        public Composite FaceTarget()
        {
            return new Decorator(ret => !DunatanksSettings.Instance.DisableMovement && (!Me.IsFacing(Me.CurrentTarget) || !Me.IsSafelyFacing(Me.CurrentTarget, 5f)),
                new Action(a => Me.CurrentTarget.Face()));
        }
        #endregion
        #region StanceCheck
        public Composite StanceChange()
        {
            return new Decorator(
                     ret => !Me.IsDead,
                     new PrioritySelector(
                        new Decorator(
                            ret => !Me.HasAura("Battle Stance") && (DunatanksSettings.Instance.useArms || DunatanksSettings.Instance.useFury),
                            new Action(ret => SpellManager.Cast("Battle Stance"))),
                        new Decorator(ret => !Me.HasAura("Defensive Stance") && DunatanksSettings.Instance.useProt,
                            new Action(ret => SpellManager.Cast("Defensive Stance")))
                         ));
        }

        #endregion
        #region PvPCC
        public bool IsPvPCrowdControlled(WoWUnit unit)
        {
            return Me.GetAllAuras().Any(
                a => a.IsHarmful &&
                     (a.Spell.Mechanic == WoWSpellMechanic.Shackled ||
                      a.Spell.Mechanic == WoWSpellMechanic.Polymorphed ||
                      a.Spell.Mechanic == WoWSpellMechanic.Horrified ||
                      a.Spell.Mechanic == WoWSpellMechanic.Rooted ||
                      a.Spell.Mechanic == WoWSpellMechanic.Frozen ||
                      a.Spell.Mechanic == WoWSpellMechanic.Stunned ||
                      a.Spell.Mechanic == WoWSpellMechanic.Fleeing ||
                      a.Spell.Mechanic == WoWSpellMechanic.Banished ||
                      a.Spell.Mechanic == WoWSpellMechanic.Sapped
                      ));
        }
        #endregion
        #region StoneFormCheck
        public bool StoneFormCheck(WoWUnit unit)
        {
            return Me.GetAllAuras().Any(
                a => a.IsHarmful &&
                     (a.Spell.Mechanic == WoWSpellMechanic.Bleeding ||
                      a.Spell.Mechanic == WoWSpellMechanic.Infected
                      ));
        }
        #endregion
        #region EscapeArtistCheck
        public bool EscapeArtistCheck(WoWUnit unit)
        {
            return Me.GetAllAuras().Any(
                a => a.IsHarmful &&
                     (a.Spell.Mechanic == WoWSpellMechanic.Rooted ||
                      a.Spell.Mechanic == WoWSpellMechanic.Slowed
                      ));
        }
        #endregion
        #region ForsakenArtistCheck
        public bool ForsakenCheck(WoWUnit unit)
        {
            return Me.GetAllAuras().Any(
                a => a.IsHarmful &&
                     (a.Spell.Mechanic == WoWSpellMechanic.Charmed ||
                      a.Spell.Mechanic == WoWSpellMechanic.Horrified ||
                      a.Spell.Mechanic == WoWSpellMechanic.Asleep
                      ));
        }
        #endregion
        #region FleeingCheck
        public bool IsFleeing(WoWUnit unit)
        {
            return Me.CurrentTarget.GetAllAuras().Any(
                a => a.Spell.Mechanic == WoWSpellMechanic.Fleeing
                );
        }
        #endregion
        #region SlowCheck
        public bool IsSlowed(WoWUnit unit)
        {
            return Me.CurrentTarget.GetAllAuras().Any(
                a => a.Spell.Mechanic == WoWSpellMechanic.Slowed
                    || a.Spell.Mechanic == WoWSpellMechanic.Invulnerable
                    || a.Spell.Mechanic == WoWSpellMechanic.Invulnerable2
                );
        }
        #endregion
        #region Trinkets
        #region Useable
        // credits to Apoc || Armed
        private static bool CanUseEquippedItem(WoWItem item)
        {
            // Check for engineering tinkers!
            string itemSpell = Lua.GetReturnVal<string>("return GetItemSpell(" + item.Entry + ")", 0);
            if (string.IsNullOrEmpty(itemSpell))
                return false;


            return item.Usable && item.Cooldown <= 0;
        }
        #endregion

        public bool CheckTrinketOne()
        {
            if (Me.Inventory.Equipped.Trinket1 != null)
            {
                if (CanUseEquippedItem(StyxWoW.Me.Inventory.Equipped.Trinket1))
                {
                    WoWItem TrinketOne = StyxWoW.Me.Inventory.Equipped.Trinket1;
                    return true;
                }
                return false;
            }
            return false;
        }

        WoWItem TrinketOne = null;

        public Composite UseTrinketOne()
        {
            return new Decorator(ret => CheckTrinketOne() && StyxWoW.Me.Inventory.Equipped.Trinket1.Cooldown == 0 && (DunatanksSettings.Instance.UseTrinketOneOnCd) || (DunatanksSettings.Instance.UseTrinketOneBelow20 && Me.CurrentTarget.HealthPercent < 20) || (IsPvPCrowdControlled(Me) && DunatanksSettings.Instance.useTrinketOneCC) || ((Me.HasAura("Bloodlust") || Me.HasAura("Heroism") || Me.HasAura("Time Warp")) && DunatanksSettings.Instance.UseTrinketOneHero),
                                 new Action(delegate
                                 {
                                     StyxWoW.Me.Inventory.Equipped.Trinket1.Use();
                                     Logging.Write("[DWCC]: Using " + TrinketOne.Name + " <--");
                                 }
                                     ));
        }

        WoWItem TrinketTwo;

        public bool CheckTrinketTwo()
        {
            if (Me.Inventory.Equipped.Trinket2 != null)
            {
                if (CanUseEquippedItem(StyxWoW.Me.Inventory.Equipped.Trinket2))
                {
                    WoWItem TrinketTwo = StyxWoW.Me.Inventory.Equipped.Trinket2;
                    return true;
                }
                return false;
            }
            return false;
        }



        public Composite UseTrinketTwo()
        {

            return new Decorator(ret => CheckTrinketTwo() && StyxWoW.Me.Inventory.Equipped.Trinket2.Cooldown == 0 && (DunatanksSettings.Instance.UseTrinketTwoOnCd) || (DunatanksSettings.Instance.UseTrinketTwoBelow20 && Me.CurrentTarget.HealthPercent < 20) || (IsPvPCrowdControlled(Me) && DunatanksSettings.Instance.useTrinketTwoCC) || ((Me.HasAura("Bloodlust") || Me.HasAura("Heroism") || Me.HasAura("Time Warp")) && DunatanksSettings.Instance.UseTrinketTwoHero),
                                 new Action(delegate
                                 {
                                     StyxWoW.Me.Inventory.Equipped.Trinket2.Use();
                                     Logging.Write("[DWCC]: Using " + TrinketTwo.Name + " <--");
                                 }
                                     ));
        }

        public bool TrinketOneReady()
        {
            if (StyxWoW.Me.Inventory.GetItemBySlot(12) != null && StyxWoW.Me.Inventory.GetItemBySlot(12).BaseAddress != null)
            {
                if (StyxWoW.Me.Inventory.GetItemBySlot(12).Cooldown == 0)
                {
                    return true;
                }
            }
            return false;
        }

        public bool TrinketTwoReady()
        {
            if (StyxWoW.Me.Inventory.GetItemBySlot(13) != null && StyxWoW.Me.Inventory.GetItemBySlot(13).BaseAddress != null)
            {
                if (StyxWoW.Me.Inventory.GetItemBySlot(13).Cooldown == 0)
                {
                    return true;
                }
            }
            return false;
        }
        #endregion
        #region AoEPummel
        public WoWUnit AoEPummelLastTarget = null;

        public Composite AoEPummel()
        {
            SetCurrentTarget();
            return new Decorator(ret => DunatanksSettings.Instance.usePummelAoEAuto && SpellManager.CanCast("Pummel", (WoWUnit)AoECastingAdds().FirstOrDefault()) && (WoWUnit)AoECastingAdds().FirstOrDefault() != null,
                                 new Sequence(
                                     TargetAoEPummel(ret => Me.CurrentTarget != ((WoWUnit)AoECastingAdds().FirstOrDefault()) && (WoWUnit)AoECastingAdds().FirstOrDefault() != null),
                                     FaceAoEPummel(ret => !Me.IsFacing((WoWUnit)AoECastingAdds().FirstOrDefault()) && (WoWUnit)AoECastingAdds().FirstOrDefault() != null),
                                     new Action(ret => SpellManager.Cast("Pummel", (WoWUnit)AoECastingAdds().FirstOrDefault())),
                                     new Action(ret => AoEPummelLastTarget.Target()),
                                     new Action(ret => AoEPummelLastTarget.Face())));
        }

        public void SetCurrentTarget()
        {
            AoEPummelLastTarget = Me.CurrentTarget;
        }

        public Composite FaceAoEPummel(CanRunDecoratorDelegate extra)
        {
            return new Decorator(ret => extra(ret) && !Me.IsFacing((WoWUnit)AoECastingAdds().FirstOrDefault()),
                                 new Action(delegate
                                 {
                                     ((WoWUnit)AoECastingAdds().FirstOrDefault()).Face();
                                     Logging.Write("[DWCC]: Facing AoE Pummel target.");
                                 }
                                     ));
        }

        public Composite TargetAoEPummel(CanRunDecoratorDelegate extra)
        {
            return new Decorator(ret => extra(ret) && Me.CurrentTarget != ((WoWUnit)AoECastingAdds().FirstOrDefault()),
                                 new Action(delegate
                                 {
                                     ((WoWUnit)AoECastingAdds().FirstOrDefault()).Target();
                                     Logging.Write("[DWCC]: Targeting AoE Pummel target.");
                                 }
                                     ));
        }
        #endregion
        #region AoECastingAdds
        private List<WoWUnit> AoECastingAdds()
        {
            List<WoWUnit> addList = ObjectManager.GetObjectsOfType<WoWUnit>(false).FindAll(unit =>
                        unit.Guid != Me.Guid &&
                        unit.Distance < DunatanksSettings.Instance.CombatDistance &&
                        unit.IsAlive &&
                        unit.Combat &&
                        unit.IsCasting &&
                        !unit.IsFriendly &&
                        !unit.IsPet &&
                        !Styx.CommonBot.Blacklist.Contains(unit.Guid));

            return addList;
        }
        #endregion
        #region HealthRegen
        public static ulong LastTarget;
        public static ulong LastTargetHPPot;
        WoWItem CurrentHealthPotion;
        public bool HaveHealthPotion()
        {
            //whole idea is to make sure CurrentHealthPotion is not null, and to check once every battle. 
            if (CurrentHealthPotion == null)
            {
                if (LastTargetHPPot == null || Me.CurrentTarget.Guid != LastTargetHPPot) //Meaning they are not the same. 
                {
                    LastTarget = Me.CurrentTarget.Guid; // set guid to current target. 
                    List<WoWItem> HPPot =
                    (from obj in
                         Me.BagItems.Where(
                             ret => ret != null && ret.BaseAddress != null &&
                             (ret.ItemInfo.ItemClass == WoWItemClass.Consumable) &&
                             (ret.ItemInfo.ContainerClass == WoWItemContainerClass.Potion) &&
                             (ret.ItemSpells[0].ActualSpell.SpellEffect1.EffectType == WoWSpellEffectType.Heal))
                     select obj).ToList();
                    if (HPPot.Count > 0)
                    {

                        //on first check, set CurrentHealthPotion so we dont keep running the list looking for one, 
                        CurrentHealthPotion = HPPot.FirstOrDefault();
                        Logging.Write("Potion Found {0}", HPPot.FirstOrDefault().Name);
                        return true;

                    }
                }


                return false;
            }
            else
            {
                return true;
            }
        }
        public bool HealthPotionReady()
        {
            if (CurrentHealthPotion != null && CurrentHealthPotion.BaseAddress != null)
            {
                if (CurrentHealthPotion.Cooldown == 0)
                {
                    return true;
                }
            }
            return false;
        }
        public void UseHealthPotion()
        {
            if (CurrentHealthPotion != null && CurrentHealthPotion.BaseAddress != null)
            {
                if (CurrentHealthPotion.Cooldown == 0)
                {
                    Logging.Write("[DWCC]: Low HP! Using --> {0} <--!", CurrentHealthPotion.Name.ToString());
                    CurrentHealthPotion.Use();
                }
            }
        }

        // credits to CodenameG
        public static WoWItem HealthStone;
        public static bool HaveHealthStone()
        {

            if (HealthStone == null)
            {
                foreach (WoWItem item in Me.BagItems)
                {
                    if (item.Entry == 5512)
                    {
                        HealthStone = item;
                        return true;
                    }

                }
                return false;
            }
            else
            {
                return true;
            }
        }

        public static bool HealthStoneNotCooldown()
        {
            if (HealthStone != null && HealthStone.BaseAddress != null)
            {

                if (HealthStone.Cooldown == 0)
                {
                    return true;
                }

            }
            return false;
        }
        public static void UseHealthStone()
        {
            if (HealthStone != null && HealthStoneNotCooldown())
            {
                Logging.Write("[DWCC]: Swallowing the green pill! Using --> Healthstone <--");
                HealthStone.Use();
            }
        }
        #endregion
        #region LifeSpirit
        public bool LifeSpiritRegen()
        {
            if ((Me.CurrentHealth <= (Me.MaxHealth - 60000)) && HaveLifeSpirit() && LifeSpiritNotCooldown() && !Me.Mounted && !Me.OnTaxi && !Me.IsFlying)
            {
                UseLifeSpirit();
                return true;
            }
            return false;
        }

        public static WoWItem LifeSpirit;
        public static bool HaveLifeSpirit()
        {

            if (LifeSpirit == null)
            {
                foreach (WoWItem item in Me.BagItems)
                {
                    if (item.Entry == 89640)
                    {
                        LifeSpirit = item;
                        return true;
                    }

                }
                return false;
            }
            else
            {
                return true;
            }
        }

        public static bool LifeSpiritNotCooldown()
        {
            if (LifeSpirit != null && LifeSpirit.BaseAddress != null)
            {

                if (LifeSpirit.Cooldown == 0)
                {
                    return true;
                }

            }
            return false;
        }
        public static void UseLifeSpirit()
        {
            if (LifeSpirit != null && LifeSpiritNotCooldown())
            {
                Logging.Write("[DWCC]: Using --> Life Spirit <--");
                LifeSpirit.Use();
            }
        }
        #endregion
        #region Racials
        #region useRacialsComposite
        public Composite UseRacialComposite()
        {
            return new Decorator(ret => !Me.IsDead && DunatanksSettings.Instance.UseRacials,
                                 new PrioritySelector(
                        new Decorator(
                            ret => Me.Race == WoWRace.Human && IsPvPCrowdControlled(Me) && SpellManager.HasSpell("Every Man for Himself") && !SpellManager.Spells["Every Man for Himself"].Cooldown && SpellManager.CanCast("Every Man for Himself"),
                            new Action(ret => SpellManager.Cast("Every Man for Himself"))),
                        new Decorator(
                            ret => Me.Race == WoWRace.NightElf && Me.IsInMyPartyOrRaid && (DunatanksSettings.Instance.useArms || DunatanksSettings.Instance.useFury) && Me.CurrentTarget.Aggro && SpellManager.HasSpell("Shadowmeld") && !SpellManager.Spells["Shadowmeld"].Cooldown && SpellManager.CanCast("Shadowmeld"),
                            new Action(ret => SpellManager.Cast("Shadowmeld"))),
                        new Decorator(
                            ret => Me.Race == WoWRace.Dwarf && StoneFormCheck(Me) && SpellManager.HasSpell("Stoneform") && !SpellManager.Spells["Stoneform"].Cooldown && SpellManager.CanCast("Stoneform"),
                            new Action(ret => SpellManager.Cast("Stoneform"))),
                        new Decorator(
                            ret => Me.Race == WoWRace.Gnome && EscapeArtistCheck(Me) && SpellManager.HasSpell("Escape Artist") && !SpellManager.Spells["Escape Artist"].Cooldown && SpellManager.CanCast("Escape Artist"),
                            new Action(ret => SpellManager.Cast("Escape Artist"))),
                        new Decorator(
                            ret => Me.Race == WoWRace.Worgen && (Me.CurrentTarget.Distance > 35 || (Me.CurrentTarget.Distance > 20 && IsFleeing(Me.CurrentTarget))) && SpellManager.HasSpell("Darkflight") && !SpellManager.Spells["Darkflight"].Cooldown && SpellManager.CanCast("Darkflight"),
                            new Action(ret => SpellManager.Cast("Darkflight"))),
                        new Decorator(
                            ret => Me.Race == WoWRace.Draenei && Me.HealthPercent < 70 && SpellManager.HasSpell("Gift of the Naaru") && !SpellManager.Spells["Gift of the Naaru"].Cooldown && SpellManager.CanCast("Gift of the Naaru"),
                            new Action(ret => SpellManager.Cast("Gift of the Naaru"))),
                //Horde
                        new Decorator(
                            ret => Me.Race == WoWRace.Orc && Me.Combat && SpellManager.HasSpell("Blood Fury") && !SpellManager.Spells["Blood Fury"].Cooldown && SpellManager.CanCast("Blood Fury"),
                            new Action(ret => SpellManager.Cast("Blood Fury"))),
                        new Decorator(
                            ret => Me.Race == WoWRace.Tauren && Me.Combat && AoECastingAdds().Count > 0 && SpellManager.HasSpell("War Stomp") && !SpellManager.Spells["War Stomp"].Cooldown && SpellManager.CanCast("War Stomp") && !Me.IsMoving,
                            new Action(ret => SpellManager.Cast("War Stomp"))),
                        new Decorator(
                            ret => Me.Race == WoWRace.Undead && ForsakenCheck(Me) && SpellManager.HasSpell("Will of the Forsaken") && !SpellManager.Spells["Will of the Forsaken"].Cooldown && SpellManager.CanCast("Will of the Forsaken"),
                            new Action(ret => SpellManager.Cast("Will of the Forsaken"))),
                        new Decorator(
                            ret => Me.Race == WoWRace.Troll && Me.Combat && SpellManager.CanCast("Berserking"),
                            new Action(ret => SpellManager.Cast("Berserking"))),
                        new Decorator(
                            ret => Me.Race == WoWRace.BloodElf && Me.Combat && AoECastingAdds().Count > 0 && SpellManager.HasSpell("Arcane Torrent") && !SpellManager.Spells["Arcane Torrent"].Cooldown && SpellManager.CanCast("Arcane Torrent"),
                            new Action(ret => SpellManager.Cast("Arcane Torrent"))),
                        new Decorator(
                            ret => Me.Race == WoWRace.Goblin && Me.Combat && Me.CurrentTarget.Attackable && Me.CurrentTarget.IsHostile && SpellManager.HasSpell("Rocket Barrage") && !SpellManager.Spells["Rocket Barrage"].Cooldown && SpellManager.CanCast("Rocket Barrage"),
                            new Action(ret => SpellManager.Cast("Rocket Barrage", Me.CurrentTarget)))
                                     ));
        }
        #endregion
        #region UseRacials
        public bool RacialAbilities()
        {
            if (DunatanksSettings.Instance.UseRacials && !Me.Mounted && !Me.OnTaxi && !Me.IsFlying && Me.CurrentTarget != null)
            {
                #region Alliance
                HumanRacial();
                NightElfRacial();
                DwarfRacial();
                GnomeRacial();
                WorgenRacial();
                DraeneiRacial();
                #endregion

                #region Horde
                OrcRacial();
                TaurenRacial();
                UndeadRacial();
                TrollRacial();
                GoblinRacial();
                BloodElfRacial();
                #endregion
                return true;
            }
            return false;
        }
        #endregion
        #region Alliance
        #region Human
        public bool HumanRacial()
        {
            if (Me.Race == WoWRace.Human && IsPvPCrowdControlled(Me) && SpellManager.HasSpell("Every Man for Himself") && !SpellManager.Spells["Every Man for Himself"].Cooldown && SpellManager.CanCast("Every Man for Himself"))
            {
                SpellManager.Cast("Every Man for Himself");
                return true;
            }
            return false;
        }
        #endregion
        #region NightElf
        public bool NightElfRacial()
        {
            if (Me.Race == WoWRace.NightElf && Me.IsInMyPartyOrRaid && (DunatanksSettings.Instance.useArms || DunatanksSettings.Instance.useFury) && Me.CurrentTarget.Aggro && SpellManager.HasSpell("Shadowmeld") && !SpellManager.Spells["Shadowmeld"].Cooldown && SpellManager.CanCast("Shadowmeld"))
            {
                SpellManager.Cast("Shadowmeld");
                return true;
            }
            return false;
        }
        #endregion
        #region Dwarf
        public bool DwarfRacial()
        {
            if (Me.Race == WoWRace.Dwarf && StoneFormCheck(Me) && SpellManager.HasSpell("Stoneform") && !SpellManager.Spells["Stoneform"].Cooldown && SpellManager.CanCast("Stoneform"))
            {
                SpellManager.Cast("Stoneform");
                return true;
            }
            return false;
        }
        #endregion
        #region Gnome
        public bool GnomeRacial()
        {
            if (Me.Race == WoWRace.Gnome && EscapeArtistCheck(Me) && SpellManager.HasSpell("Escape Artist") && !SpellManager.Spells["Escape Artist"].Cooldown && SpellManager.CanCast("Escape Artist"))
            {
                SpellManager.Cast("Escape Artist");
                return true;
            }
            return false;
        }
        #endregion
        #region Worgen
        public bool WorgenRacial()
        {
            if (Me.Race == WoWRace.Worgen && (Me.CurrentTarget.Distance > 35 || (Me.CurrentTarget.Distance > 20 && IsFleeing(Me.CurrentTarget))) && SpellManager.HasSpell("Darkflight") && !SpellManager.Spells["Darkflight"].Cooldown && SpellManager.CanCast("Darkflight"))
            {
                SpellManager.Cast("Darkflight");
                return true;
            }
            return false;
        }
        #endregion
        #region Draenei
        public bool DraeneiRacial()
        {
            if (Me.Race == WoWRace.Draenei && Me.HealthPercent < 70 && SpellManager.HasSpell("Gift of the Naaru") && !SpellManager.Spells["Gift of the Naaru"].Cooldown && SpellManager.CanCast("Gift of the Naaru"))
            {
                SpellManager.Cast("Gift of the Naaru");
                return true;
            }
            return false;
        }
        #endregion
        #endregion
        #region Horde
        #region Orc
        public bool OrcRacial()
        {
            if (Me.Race == WoWRace.Orc && Me.Combat && SpellManager.HasSpell("Blood Fury") && !SpellManager.Spells["Blood Fury"].Cooldown && SpellManager.CanCast("Blood Fury"))
            {
                SpellManager.Cast("Blood Fury");
                return true;
            }
            return false;
        }
        #endregion
        #region Tauren
        public bool TaurenRacial()
        {
            if (Me.Race == WoWRace.Tauren && Me.Combat && AoECastingAdds().Count > 0 && SpellManager.HasSpell("War Stomp") && !SpellManager.Spells["War Stomp"].Cooldown && SpellManager.CanCast("War Stomp") && !Me.IsMoving)
            {
                SpellManager.Cast("War Stomp");
                return true;
            }
            return false;
        }
        #endregion
        #region Undead
        public bool UndeadRacial()
        {
            if (Me.Race == WoWRace.Undead && ForsakenCheck(Me) && SpellManager.HasSpell("Will of the Forsaken") && !SpellManager.Spells["Will of the Forsaken"].Cooldown && SpellManager.CanCast("Will of the Forsaken"))
            {
                SpellManager.Cast("Will of the Forsaken");
                return true;
            }
            return false;
        }
        #endregion
        #region Troll
        public bool TrollRacial()
        {
            if (Me.Race == WoWRace.Troll && Me.Combat && SpellManager.HasSpell("Berserking") && !SpellManager.Spells["Berserking"].Cooldown && SpellManager.CanCast("Berserking"))
            {
                SpellManager.Cast("Berserking");
                return true;
            }
            return false;
        }
        #endregion
        #region Goblin
        public bool GoblinRacial()
        {
            if (Me.Race == WoWRace.Goblin && Me.Combat && Me.CurrentTarget.Attackable && Me.CurrentTarget.IsHostile && SpellManager.HasSpell("Rocket Barrage") && !SpellManager.Spells["Rocket Barrage"].Cooldown && SpellManager.CanCast("Rocket Barrage"))
            {
                SpellManager.Cast("Rocket Barrage", Me.CurrentTarget);
                return true;
            }
            return false;
        }
        #endregion
        #region BloodElf
        public bool BloodElfRacial()
        {
            if (Me.Race == WoWRace.BloodElf && Me.Combat && AoECastingAdds().Count > 0 && SpellManager.HasSpell("Arcane Torrent") && !SpellManager.Spells["Arcane Torrent"].Cooldown && SpellManager.CanCast("Arcane Torrent"))
            {
                SpellManager.Cast("Arcane Torrent");
                return true;
            }
            return false;
        }
        #endregion
        #endregion
        #region Neutral
        #region Pandaren
        // Currently, there are no advantages for using Pandaren racial skills
        #endregion
        #endregion
        #endregion
        #region AreaSpells
        #region Bool
        public bool AreaSpells()
        {
            if (StyxWoW.Me.HasAura(130774) ||
        StyxWoW.Me.HasAura(116040) ||
        StyxWoW.Me.HasAura(116583) ||
        StyxWoW.Me.HasAura(116586) ||
        StyxWoW.Me.HasAura(116924) ||
        StyxWoW.Me.HasAura(119610) ||
        StyxWoW.Me.HasAura(13810) ||
        StyxWoW.Me.HasAura(43265))
            {
                Logging.WriteDiagnostic("[DWCC]: Standing in AoE: true.");
                return true;
            }
            else
            {
                return false;
            }
        }
        #endregion
        #region FindHealers
        public List<WoWPlayer> Healers
        {
            get
            {
                if (!StyxWoW.Me.GroupInfo.IsInParty)
                    return new List<WoWPlayer>(); ;

                return StyxWoW.Me.GroupInfo.RaidMembers.Where(p => p.HasRole(WoWPartyMember.GroupRole.Healer))
                    .Select(p => p.ToPlayer())
                    .Where(p => p != null && p.IsAlive && p.IsFriendly && (!p.HasAura(130774) || !p.HasAura(116040) || !p.HasAura(116583) || !p.HasAura(116586) || !p.HasAura(116924) || !p.HasAura(119610) || !p.HasAura(13810) || !p.HasAura(43265)) && Navigator.CanNavigateFully(Me.Location, p.Location)).ToList();
            }
        }
        #endregion
        #region MoveOut
        public Composite MoveOutOfAoE()
        {
            return new Decorator(ret => AreaSpells() && !DunatanksSettings.Instance.DisableMovement && !(Me.Specialization == WoWSpec.WarriorProtection) && DunatanksSettings.Instance.MoveOutOfAoE,
                                 new Action(delegate
                                 {
                                     Logging.Write("[DWCC]: Moving out of AoE.");
                                     //Logging.Write("[DWCC]: Healer: " + Healers.FirstOrDefault().ToString() + " | CanNav: " + Navigator.CanNavigateFully(Me.Location, Healers.FirstOrDefault().Location));
                                     Navigator.PlayerMover.MoveTowards(Healers.FirstOrDefault().Location);
                                 }
                                ));
        }

        public Composite StopAoEMovement()
        {
            {
                return new Decorator(ret => !AreaSpells() && !DunatanksSettings.Instance.DisableMovement && MoveOutOfAoE().IsRunning && Me.IsMoving,
                                     new Action(delegate
                                     {
                                         Navigator.PlayerMover.MoveStop();
                                     }
                                    ));
            }
        }
        #endregion
        #endregion
        #region HealInterrupt
        public bool HealCast()
        {
            return Me.CurrentTarget.IsCastingHealingSpell;
        }
        #endregion
    }
}